// 1.7 authenticateUserUsingCode
// 1.8.1刷新userToken
use anyhow::anyhow;
use chrono::Duration;
// use anyhow::Ok;
use serde::{Serialize, Deserialize};
use reqwest::Client;
use crate::db_select;
use crate::db_insert;
use anyhow::Result;
use std::result::Result::{Ok,Err};
use std::str::FromStr;
use chrono::{Utc,DateTime};

#[derive(Debug, Serialize, Deserialize)]
struct Payload{
    client_id: String,
    code: String,
    code_verifier: String,
    grant_type: String,
    redirect_uri: String,
    scope: String
}
#[derive(Debug, Serialize, Deserialize)]
struct refresh_payload{
    client_id: String,
    grant_type: String,
    refresh_token: String,
    scope: String
}

#[derive(Debug, Serialize, Deserialize)]
struct response{
    access_token: String,
    refresh_token: String,
    expires_in: i64,
}
use crate::api::get_code_challange::CodeChallenge;
pub async fn get_user_token() ->  Result<String> {
    {
        match db_select("user_token_not_after").await {
            Ok(time_value) => {
                let now = Utc::now();
                let user_token_not_after = time_value.value;
                let user_token_not_after:DateTime<Utc> = DateTime::from_str(&user_token_not_after).unwrap();

                if(now < user_token_not_after){
                    // 没过期
                    let user_token_access_token = db_select("user_token_access_token").await.unwrap().value;
                    return Ok(user_token_access_token);
                } else {
                    // 存放过期重新请求
                    return Ok(refresh_token().await.unwrap());
                }
            }
            Err(_) => {}
        }
    }
    let payload = Payload{
        client_id: "000000004c20a908".to_string(),
        code: db_select("sisu_code").await.expect("未获取到sisu_code, 请确认已经登陆微软帐号").value,
        code_verifier: CodeChallenge::new().await.verifier,
        grant_type: "authorization_code".to_string(),
        redirect_uri: "ms-xal-000000004c20a908://auth".to_string(),
        scope: "service::user.auth.xboxlive.com::MBI_SSL".to_string(),
    };
    let encoded = serde_urlencoded::to_string(payload).unwrap();
    let client = Client::new();

    let response = client.post("https://login.live.com/oauth20_token.srf")
        .header("Content-Type", "application/x-www-form-urlencoded")
        .header("Cache-Control", "no-store, must-revalidate, no-cache")
        .body(encoded)
        .send().await?;

    let response_code = response.status().as_u16();
    let response_text = response.text().await?;

    match response_code {
        200 => {
            let response :response = serde_json::from_str(&response_text)?;
            let user_token_expires_in = response.expires_in;
            let now = Utc::now();
            let user_token_not_after = now + Duration::seconds(user_token_expires_in);
            let user_token_not_after = user_token_not_after.to_rfc3339();
            let user_token_access_token = response.access_token;
            let user_token_refresh_token = response.refresh_token;
            db_insert("user_token_access_token", &user_token_access_token).await?;
            db_insert("user_token_refresh_token", &user_token_refresh_token).await?;
            db_insert("user_token_not_after", &user_token_not_after).await?;

            return Ok(user_token_access_token);
        }
        _ => {
            return Err(anyhow!("Failed to get user token. Response code: {}", response_code));
        }
    }

}

// 用于刷新用户token
async fn refresh_token() -> Result<String> {

    let refresh_payload = refresh_payload{
        client_id: "000000004c20a908".to_string(),
        grant_type: "refresh_token".to_string(),
        refresh_token: db_select("user_token_refresh_token").await?.value,
        scope: "service::user.auth.xboxlive.com::MBI_SSL".to_string()
    };
    let encoded = serde_urlencoded::to_string(refresh_payload).unwrap();

    let client = Client::new();

    let response = client.post("https://login.live.com/oauth20_token.srf")
        .header("Content-Type", "application/x-www-form-urlencoded")
        .header("Cache-Control", "no-store, must-revalidate, no-cache")
        .body(encoded)
        .send().await?;
    let response_code = response.status().as_u16();
    let response_text = response.text().await?;
    match response_code {
        200 => {
            let response:response = serde_json::from_str(&response_text).unwrap();
            let user_token_expires_in = response.expires_in;
            let user_token_not_after = Utc::now() + Duration::seconds(user_token_expires_in);
            let user_token_not_after = user_token_not_after.to_rfc3339();
            let user_token_access_token = response.access_token;
            let user_token_refresh_token = response.refresh_token;
            db_insert("user_token_access_token", &user_token_access_token).await?;
            db_insert("user_token_refresh_token", &user_token_refresh_token).await?;
            db_insert("user_token_not_after", &user_token_not_after).await?;

            return Ok(user_token_access_token);
        }
        _  => {
            return Err(anyhow!("failed to refresh user_token, response code: {}",response_code));
        }
    }
}